package orchestration.android.execution.tasks;

import java.util.ArrayList;
import java.util.List;

import orchestration.android.RunExecutionActivity;
import orchestration.android.execution.commands.CommandFactory;
import orchestration.android.execution.exceptions.TaskExecutionException;

import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

/**
 * @author  <a href="mailto:car.ferrarini@gmail.com">Carlo Ferrarini</a>
 */
public class ServiceBinderTask extends AndroidTask {

	private static final String TAG ="ServiceBinderTask";
	/**
	 * @uml.property  name="intent"
	 */
	private Intent intent;
	/**
	 * @uml.property  name="flags"
	 */
	private int flags;
	/**
	 * @uml.property  name="aidl"
	 * @uml.associationEnd  
	 */
	private AidlFile aidl;
	private List<ServiceOperation> operations;
	
	public ServiceBinderTask(String id) {
		super(id);
		this.operations=new ArrayList<ServiceOperation>();
	}

	public void manageConnection(IBinder service, RunExecutionActivity atl) throws RemoteException {
			if(aidl!=null)
				for(ServiceOperation op : operations)
					op.exec(aidl,service,atl);
	}

	@Override
	public void onExecute(final RunExecutionActivity rea) throws TaskExecutionException {
		if(rea.getPackageManager().queryIntentServices(intent, PackageManager.GET_RESOLVED_FILTER).size()==0)
			throw new TaskExecutionException("Cannot find services to handle the intent");
		
		ServiceConnection conn= new ServiceConnection() {
			@Override
			public void onServiceDisconnected(ComponentName name) {
				Log.i(TAG, "onServiceDisconnected");
				rea.handleException(new TaskExecutionException("Service disconnected"));
			}
			@Override
			public void onServiceConnected(ComponentName name, IBinder service) {
				Log.i(TAG, "onServiceConnected");
				try {
					manageConnection(service,rea);
				} catch (RemoteException e) {
					rea.handleException(e);
					return;
				}
				rea.unbindService(this);
				rea.setCurrentCommand(CommandFactory.createCommand(CommandFactory.RESUME_EXECUTION));
				rea.executeNextCommand();
			}
		};
		rea.bindService(intent, conn, Service.BIND_AUTO_CREATE);
	}
	public void addOperation(ServiceOperation op){
		this.operations.add(op);
	}
	/**
	 * @param intent
	 * @uml.property  name="intent"
	 */
	public void setIntent(Intent intent) {
		this.intent = intent;
	}

	/**
	 * @return
	 * @uml.property  name="intent"
	 */
	public Intent getIntent() {
		return intent;
	}

	/**
	 * @param aidl
	 * @uml.property  name="aidl"
	 */
	public void setAidl(AidlFile aidl) {
		this.aidl = aidl;
	}

	/**
	 * @return
	 * @uml.property  name="aidl"
	 */
	public AidlFile getAidl() {
		return aidl;
	}

	/**
	 * @param flags
	 * @uml.property  name="flags"
	 */
	public void setFlags(int flags) {
		this.flags = flags;
	}

	/**
	 * @return
	 * @uml.property  name="flags"
	 */
	public int getFlags() {
		return flags;
	}
	public void createOperation(String opName, String opOutputName,
			String[] opParams) {
		Log.i(TAG, "create operation " + opName);
		int opCode= aidl.getMethodId(opName);
		String outputId=getArtifactName(opOutputName);
		List<String>inputIds= new ArrayList<String>();
		if(opParams!=null){
			for(String param : opParams)
				inputIds.add(getArtifactName(param));
		}
		ServiceOperation operation= new ServiceOperation();
		operation.setOpCode(opCode);
		operation.setInputId(inputIds);
		operation.setOutputId(outputId);
		operations.add(operation);
	}

}
